package org.taoge;

import cn.hutool.core.date.DateUtil;

import java.sql.Connection;
import java.sql.SQLException;


/**
 * 不同版本执行情况完全不同
 * 8.4.0版本，当1拿到锁之后，2不去拿锁，而是等1整个执行完，2才会拿到锁。1和2都执行成功
 * 其他版本：1和2先拿到锁，然后检测到死锁后，会让一个成功，一个回退
 */
public class JdbcDeadLock {

    public static void main(String[] args) {
        /** 8.4.0b版本运行如下
         * 线程：11获取数据库链接对象：com.mysql.cj.jdbc.ConnectionImpl@10846303
         * 线程：12获取数据库链接对象：com.mysql.cj.jdbc.ConnectionImpl@2180db2d
         * 2024-05-28 11:13:48    id1拿到锁
         * 2024-05-28 11:13:50    id1事务提交成功
         * 2024-05-28 11:13:50    id2拿到锁
         * 2024-05-28 11:13:52    id2事务提交成功
         */
        new Thread(JdbcDeadLock::lock1Update2).start();
        new Thread(JdbcDeadLock::lock2Update1).start();
    }


    public static void lock1Update2() {
        Connection conn = null;
        try {
            // 使用工具类获取连接
            conn = DatabaseUtil.getConnection();

            // 设置自动提交为false，开始事务管理
            conn.setAutoCommit(false);

            // 悲观行锁操作...
            String querySql = "SELECT id FROM user WHERE id = 1 for update";
            conn.prepareStatement(querySql).executeQuery();
            System.out.println(DateUtil.now()+"    "+"id1拿到锁");

            //沉睡一会，等另一个线程拿到2的锁
            try {
                Thread.sleep(1000);
            }catch (InterruptedException e2){
                System.out.println(e2.getMessage());
            }

            // 执行更新...
            String updateSql = "update user set name = '2' where id = 2";
            conn.prepareStatement(updateSql).executeUpdate();

            // 提交事务
            conn.commit();
            System.out.println(DateUtil.now()+"    "+"id1事务提交成功");
        } catch (SQLException e) {
            System.out.println(e.getMessage());
            // 如果发生异常，回滚事务
            if (conn != null) {
                try {
                    conn.rollback();
                    System.out.println("id1事务回滚");
                } catch (SQLException sqlException) {
                    System.out.println(sqlException.getMessage());
                }
            }
        } finally {
            // 使用工具类关闭连接
            DatabaseUtil.closeConnection(conn);
        }
    }

    public static void lock2Update1() {
        Connection conn = null;
        try {
            // 使用工具类获取连接
            conn = DatabaseUtil.getConnection();

            // 设置自动提交为false，开始事务管理
            conn.setAutoCommit(false);

            // 悲观行锁操作...
            String querySql = "SELECT id FROM user WHERE id = 2 for update";
            conn.prepareStatement(querySql).executeQuery();
            System.out.println(DateUtil.now()+"    "+"id2拿到锁");

            //沉睡一会，等另一个线程拿到2的锁
            try {
                Thread.sleep(2000);
            }catch (InterruptedException e2){
                System.out.println(e2.getMessage());
            }

            // 执行更新...
            String updateSql = "update user set name = '1' where id = 1";
            conn.prepareStatement(updateSql).executeUpdate();

            // 提交事务
            conn.commit();
            System.out.println(DateUtil.now()+"    "+"id2事务提交成功");
        } catch (SQLException e) {
            System.out.println(e.getMessage());
            // 如果发生异常，回滚事务
            if (conn != null) {
                try {
                    conn.rollback();
                    System.out.println(DateUtil.now()+"    "+"id2事务回滚");
                } catch (SQLException sqlException) {
                    System.out.println(sqlException.getMessage());
                }
            }
        } finally {
            // 使用工具类关闭连接
            DatabaseUtil.closeConnection(conn);
        }
    }
}